home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
ole2book.zip
/
CHAP11.ZIP
/
CHAP11
/
POLYLINE
/
POLYLINE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-22
|
17KB
|
736 lines
/*
* POLYLINE.CPP
* Polyline Component Object Chapter 11
*
* Implementation of the CPolyline class that we expose as an
* OLE 2.0 component object.
*
* Copyright (c)1993 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Software Design Engineer
* Microsoft Systems Developer Relations
*
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "polyline.h"
/*
* CPolyline:CPolyline
* CPolyline::~CPolyline
*
* Constructor Parameters:
* punkOuter LPUNKNOWN of the controlling unknown.
* pfnDestroy LPFNDESTROYED to call when an object is destroyed.
* hInst HINSTANCE of the application we're in.
*/
CPolyline::CPolyline(LPUNKNOWN punkOuter, LPFNDESTROYED pfnDestroy
, HINSTANCE hInst)
{
m_hWnd=NULL;
m_hInst=hInst;
m_cRef=0;
m_punkOuter=punkOuter;
m_pfnDestroy=pfnDestroy;
m_fDirty=FALSE;
m_pST=NULL;
m_cf =0;
m_clsID=CLSID_Polyline11;
m_iID =IID_IPolyline6;
//NULL any contained interfaces initially.
m_pIPolyline =NULL;
m_pIPersistStorage =NULL;
m_pIDataObject =NULL;
m_pIDataAdviseHolder=NULL;
m_pAdv =NULL;
//Initialize IDataObject::EnumFormatEtc arrays
m_cf=RegisterClipboardFormat(SZPOLYLINECLIPFORMAT);
//CHAPTER11MOD
m_pDefIUnknown =NULL;
m_pDefIOleObject =NULL;
m_pDefIDataObject =NULL;
m_pDefIViewObject =NULL;
m_pDefIPersistStorage=NULL;
m_pIOleAdviseHolder =NULL;
m_pIOleObject =NULL;
m_pIOleClientSite =NULL;
m_pIViewObject =NULL;
m_pIAdviseSink =NULL;
m_dwFrozenAspects =0;
m_dwAdviseAspects =0;
m_dwAdviseFlags =0;
m_hDlg=NULL;
//End CHAPTER11MOD
return;
}
CPolyline::~CPolyline(void)
{
if (NULL!=m_pST)
delete m_pST;
//CHAPTER11MOD
if (NULL!=m_hDlg)
DestroyWindow(m_hDlg);
if (NULL!=m_pDefIUnknown)
m_pDefIUnknown->Release();
if (NULL!=m_pDefIOleObject)
m_pDefIOleObject->Release();
if (NULL!=m_pDefIViewObject)
m_pDefIViewObject->Release();
if (NULL!=m_pDefIDataObject)
m_pDefIDataObject->Release();
if (NULL!=m_pDefIPersistStorage)
m_pDefIPersistStorage->Release();
if (NULL!=m_pIAdviseSink)
m_pIAdviseSink->Release();
if (NULL!=m_pIViewObject)
delete m_pIViewObject;
if (NULL!=m_pIOleClientSite)
m_pIOleClientSite->Release();
if (NULL!=m_pIOleAdviseHolder)
m_pIOleAdviseHolder->Release();
if (NULL!=m_pIOleObject)
delete m_pIOleObject;
//End CHAPTER11MOD
//Free our contained interfaces, delete those we own, Release others.
if (NULL!=m_pIDataAdviseHolder)
m_pIDataAdviseHolder->Release();
if (NULL!=m_pIDataObject)
delete m_pIDataObject;
if (NULL!=m_pIPersistStorage)
delete m_pIPersistStorage;
if (NULL!=m_pIPolyline)
delete m_pIPolyline;
//Reverses the AddRef in ::SetAdvise
if (NULL!=m_pAdv)
m_pAdv->Release();
return;
}
/*
* CPolyline::FInit
*
* Purpose:
* Performs any intiailization of a CPolyline that's prone to failure
* that we also use internally before exposing the object outside
* this DLL.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if the function is successful, FALSE otherwise.
*/
BOOL CPolyline::FInit(void)
{
LPUNKNOWN pIUnknown=(LPUNKNOWN)this;
HRESULT hr;
if (NULL!=m_punkOuter)
pIUnknown=m_punkOuter;
m_pST=new CStringTable(m_hInst);
if (!m_pST->FInit(IDS_POLYLINEMIN, IDS_POLYLINEMAX))
return FALSE;
//Allocate contained interfaces.
m_pIPolyline=new CImpIPolyline(this, pIUnknown);
if (NULL==m_pIPolyline)
return FALSE;
m_pIPersistStorage=new CImpIPersistStorage(this, pIUnknown);
if (NULL==m_pIPersistStorage)
return FALSE;
m_pIDataObject=new CImpIDataObject(this, pIUnknown);
if (NULL==m_pIDataObject)
return FALSE;
//CHAPTER11MOD
m_pIOleObject=new CImpIOleObject(this, pIUnknown);
if (NULL==m_pIOleObject)
return FALSE;
m_pIViewObject=new CImpIViewObject(this, pIUnknown);
if (NULL==m_pIViewObject)
return FALSE;
//Get stuff from the default handler so we get some free implementation
hr=OleCreateDefaultHandler(CLSID_Polyline11, pIUnknown, IID_IUnknown
, (LPLPVOID)&m_pDefIUnknown);
if (FAILED(hr))
return FALSE;
//Now try to get other interfaces to which we delegate
hr=m_pDefIUnknown->QueryInterface(IID_IOleObject
, (LPLPVOID)&m_pDefIOleObject);
if (FAILED(hr))
return FALSE;
hr=m_pDefIUnknown->QueryInterface(IID_IViewObject
, (LPLPVOID)&m_pDefIViewObject);
if (FAILED(hr))
return FALSE;
hr=m_pDefIUnknown->QueryInterface(IID_IDataObject
, (LPLPVOID)&m_pDefIDataObject);
if (FAILED(hr))
return FALSE;
hr=m_pDefIUnknown->QueryInterface(IID_IPersistStorage
, (LPLPVOID)&m_pDefIPersistStorage);
if (FAILED(hr))
return FALSE;
m_pIPolyline->New();
//End CHAPTER11MOD
return TRUE;
}
/*
* CPolyline::QueryInterface
* CPolyline::AddRef
* CPolyline::Release
*
* Purpose:
* IUnknown members for CPolyline object.
*/
STDMETHODIMP CPolyline::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
*ppv=NULL;
/*
* The only calls we get here for IUnknown are either in a non-aggregated
* case or when we're created in an aggregation, so in either we always
* return our IUnknown for IID_IUnknown.
*/
if (IsEqualIID(riid, IID_IUnknown))
*ppv=(LPVOID)this;
//For anything else we return contained interfaces.
if (IsEqualIID(riid, m_iID))
*ppv=(LPVOID)m_pIPolyline;
if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IPersistStorage))
*ppv=(LPVOID)m_pIPersistStorage;
if (IsEqualIID(riid, IID_IDataObject))
*ppv=(LPVOID)m_pIDataObject;
//CHAPTER11MOD
if (IsEqualIID(riid, IID_IOleObject))
*ppv=(LPVOID)m_pIOleObject;
if (IsEqualIID(riid, IID_IViewObject))
*ppv=(LPVOID)m_pIViewObject;
//Use the default handler's cache.
if (IsEqualIID(riid, IID_IOleCache))
return m_pDefIUnknown->QueryInterface(riid, ppv);
//End CHAPTER11MOD
//AddRef any interface we'll return.
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CPolyline::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CPolyline::Release(void)
{
ULONG cRefT;
cRefT=--m_cRef;
if (0==m_cRef)
delete this;
return cRefT;
}
/*
* CPolyline::RectConvertMappings
*
* Purpose:
* Converts the contents of a rectangle from device (MM_TEXT) or
* HIMETRIC to the other.
*
* Parameters:
* pRect LPRECT containing the rectangle to convert.
* fToDevice BOOL TRUE to convert from HIMETRIC to device,
* FALSE to convert device to HIMETRIC.
*
* Return Value:
* None
*/
void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
{
HDC hDC;
int iLpx, iLpy;
if (NULL==pRect)
return;
hDC=GetDC(NULL);
iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
ReleaseDC(NULL, hDC);
if (fToDevice)
{
pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
pRect->right =MulDiv(iLpx, pRect->right, HIMETRIC_PER_INCH);
pRect->bottom=MulDiv(iLpy, pRect->bottom, HIMETRIC_PER_INCH);
}
else
{
pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
pRect->bottom=MulDiv(pRect->bottom, HIMETRIC_PER_INCH, iLpy);
}
return;
}
/*
* CPolyline::DataSet
*
* Purpose:
* Sets the current data in this Polyline to a given structure.
*
* Parameters:
* pplIn LPPOLYLINEDATA to initialize to.
* fSizeToData BOOL indicating if we're to size to the data or scale it.
* fNotify BOOL indicating if we're to send an advise on this change.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise a POLYLINE_E_ value.
*/
STDMETHODIMP CPolyline::DataSet(LPPOLYLINEDATA pplIn, BOOL fSizeToData
, BOOL fNotify)
{
RECT rc;
/*
* Copy the structure in pplIn and repaint to reflect the new point
* set. Note that unlike the RectSet message, we do no scaling,
* assuming that the rect in the structure is appropriate for the data.
*/
if (NULL==pplIn)
return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
//Preserve the old rectangle, then copy
rc=m_pl.rc;
m_pl=*pplIn;
m_fDirty=TRUE;
/*
* If we're scaling the window to fit the data, then use
* RectSet passing our current rectangle as the new one.
* That makes sure that the data won't change but that the
* window is resized.
*/
if (fSizeToData)
{
POINT pt;
/*
* Get our offset in the parent window so we can RectSet
* to the right place since RectSet expects rectangle in
* parent coordinates and we get it in client coordinates.
*/
GetWindowRect(m_hWnd, &rc);
pt.x=rc.left;
pt.y=rc.top;
ScreenToClient(GetParent(m_hWnd), &pt);
rc=m_pl.rc;
OffsetRect(&rc, pt.x, pt.y);
//This will also cause a repaint.
m_pIPolyline->RectSet(&rc, fNotify);
}
else
{
//Make sure we're updated.
InvalidateRect(m_hWnd, NULL, TRUE);
UpdateWindow(m_hWnd);
}
//CHAPTER11MOD
SendAdvise(OBJECTCODE_DATACHANGED);
//End CHAPTER11MOD
return NOERROR;
}
/*
* CImpIPolyline::DataGet
*
* Purpose:
* Retrieves the Polyline's current data.
*
* Parameters:
* pplIn LPPOLYLINEDATA into which we copy the data.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise a POLYLINE_E_ value.
*/
STDMETHODIMP CPolyline::DataGet(LPPOLYLINEDATA pplIn)
{
if (NULL==pplIn)
return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
*pplIn=m_pl;
return NOERROR;
}
/*
* CPolyline::RenderNative
*
* Purpose:
* Retrieves the Polyline's data in a global memory handle.
*
* Parameters:
* phMem HGLOBAL FAR * in which to store the handle.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise a POLYLINE_E_ value.
*/
STDMETHODIMP CPolyline::RenderNative(HGLOBAL FAR *phMem)
{
HGLOBAL hMem;
LPPOLYLINEDATA ppl;
HRESULT hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
if (NULL==phMem)
return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, CBPOLYLINEDATA);
if (NULL!=hMem)
{
ppl=(LPPOLYLINEDATA)GlobalLock(hMem);
hr=DataGet(ppl);
GlobalUnlock(hMem);
if (FAILED(hr))
{
GlobalFree(hMem);
hMem=NULL;
}
}
*phMem=hMem;
return hr;
}
/*
* CPolyline::RenderBitmap
*
* Purpose:
* Creates a bitmap image of the current Polyline.
*
* Parameters:
* phBmp HBITMAP FAR * in which to return the bitmap.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise a POLYLINE_E_ value.
*/
STDMETHODIMP CPolyline::RenderBitmap(HBITMAP FAR *phBmp)
{
HDC hDC;
HDC hMemDC;
HBITMAP hBmp;
RECT rc;
HGDIOBJ hObj;
if (NULL==phBmp)
return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
//Render a bitmap the size of the current rectangle.
hDC=GetDC(m_hWnd);
hMemDC=CreateCompatibleDC(hDC);
GetClientRect(m_hWnd, &rc);
hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
if (NULL!=hBmp)
{
//Draw the POLYLINEDATA into the bitmap.
hObj=SelectObject(hMemDC, hBmp);
Draw(hMemDC, FALSE, TRUE, &rc, NULL);
SelectObject(hMemDC, hObj);
}
DeleteDC(hMemDC);
ReleaseDC(m_hWnd, hDC);
*phBmp=hBmp;
return NOERROR;
}
/*
* CPolyline::RenderMetafilePict
*
* Purpose:
* Renders the current Polyline into a METAFILEPICT structure in
* global memory.
*
* Parameters:
* phMem HGLOBAL FAR * in which to return the METAFILEPICT.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise a POLYLINE_E_ value.
*/
STDMETHODIMP CPolyline::RenderMetafilePict(HGLOBAL FAR * phMem)
{
HGLOBAL hMem;
HMETAFILE hMF;
HDC hDC;
LPMETAFILEPICT pMF;
RECT rc;
if (NULL==phMem)
return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
hMF=NULL;
//Create a memory metafile and return its handle.
hDC=(HDC)CreateMetaFile(NULL);
if (NULL==hDC)
return ResultFromScode(STG_E_MEDIUMFULL);
SetMapMode(hDC, MM_ANISOTROPIC);
GetClientRect(m_hWnd, &rc);
SetWindowOrg(hDC, 0, 0);
SetWindowExt(hDC, rc.right, rc.bottom);
Draw(hDC, TRUE, TRUE, &rc, NULL);
hMF=CloseMetaFile(hDC);
if (NULL==hMF)
return ResultFromScode(STG_E_MEDIUMFULL);
//Allocate the METAFILEPICT structure.
hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
if (NULL==hMem)
{
DeleteMetaFile(hMF);
return ResultFromScode(E_FAIL);
}
/*
* Global lock only fails in PMODE if the selector is invalid
* (like it was discarded) or references a 0 length segment,
* neither of which can happen here.
*/
pMF=(LPMETAFILEPICT)GlobalLock(hMem);
pMF->hMF=hMF;
pMF->mm=MM_ANISOTROPIC;
//Insert the extents in MM_HIMETRIC units.
GetClientRect(m_hWnd, &rc);
RectConvertMappings(&rc, FALSE);
pMF->xExt=rc.right;
pMF->yExt=rc.bottom;
GlobalUnlock(hMem);
*phMem=hMem;
return NOERROR;
}
//CHAPTER11MOD
/*
* CFigure::SendAdvise
*
* Purpose:
* Calls the appropriate IOleClientSite or IAdviseSink member function
* for various events such as closure, renaming, saving, etc.
*
* Parameters:
* uCode UINT OBJECTCODE_* identifying the notification.
*
* Return Value:
* None
*/
void CPolyline::SendAdvise(UINT uCode)
{
DWORD dwAspect=DVASPECT_CONTENT | DVASPECT_THUMBNAIL;
switch (uCode)
{
case OBJECTCODE_SAVED:
if (NULL!=m_pIOleAdviseHolder)
m_pIOleAdviseHolder->SendOnSave();
break;
case OBJECTCODE_CLOSED:
if (NULL!=m_pIOleAdviseHolder)
m_pIOleAdviseHolder->SendOnClose();
break;
case OBJECTCODE_RENAMED:
//Call IOleAdviseHolder::SendOnRename (later)
break;
case OBJECTCODE_SAVEOBJECT:
if (m_fDirty && NULL!=m_pIOleClientSite)
m_pIOleClientSite->SaveObject();
break;
case OBJECTCODE_DATACHANGED:
//No flags are necessary here.
if (NULL!=m_pIDataAdviseHolder)
m_pIDataAdviseHolder->SendOnDataChange(m_pIDataObject, 0, 0);
if (NULL!=m_pIAdviseSink & (dwAspect & m_dwAdviseAspects))
m_pIAdviseSink->OnViewChange(dwAspect & m_dwAdviseAspects, 0);
break;
case OBJECTCODE_SHOWWINDOW:
if (NULL!=m_pIOleClientSite)
m_pIOleClientSite->OnShowWindow(TRUE);
break;
case OBJECTCODE_HIDEWINDOW:
if (NULL!=m_pIOleClientSite)
m_pIOleClientSite->OnShowWindow(FALSE);
break;
case OBJECTCODE_SHOWOBJECT:
if (NULL!=m_pIOleClientSite)
m_pIOleClientSite->ShowObject();
break;
}
return;
}
//End CHAPTER11MOD